#!/usr/bin/env ruby

# Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
# This code is released under a tri EPL/GPL/LGPL license. You can use it,
# redistribute it and/or modify it under the terms of the:
#
# Eclipse Public License version 1.0
# GNU General Public License version 2
# GNU Lesser General Public License version 2.1

require 'ostruct'
require 'yaml'
require 'erb'


def camelize(string)
  string.sub(/^([a-z\d]*)/) { $1.capitalize }.gsub(/_([a-z\d]*)/) { $1.capitalize }
end

options_data = YAML.load_file('tool/options.yml')

options = options_data.map do |constant, values|
  raise "More or less than 4 arguments in #{values} for #{constant}" unless values.size == 4
  (name, *mri_names), type, default, description = values

  case type
  when 'boolean'
    type       = 'boolean'
    boxed_type = 'Boolean'
    default    = default.to_s
  when 'integer'
    type       = 'int'
    boxed_type = 'Integer'
    default    = default.to_s
  when /^enum\/(\w*)/
    name       = $1
    type       = camelize name
    boxed_type = type
    default    = "#{type}.#{default.to_s.upcase}"
  when 'string'
    type       = 'String'
    boxed_type = type
    default    = default.nil? ? 'null' : "\"#{default.to_s}\""
  when 'string-array'
    type             = 'String[]'
    boxed_type       = type
    type_description = 'StringArrayOptionDescription'
    default          = "new String[]{#{default.map(&:inspect).join(', ')}}"
  else
    raise type.to_s
  end

  OpenStruct.new(
      constant:          constant,
      name:              name,
      mri_names:         mri_names,
      type:              type,
      type_description:  type_description || "#{boxed_type}OptionDescription",
      boxed_type:        boxed_type,
      default:           default,
      reference_default: /^!?[A-Z_]+$/.match(default),
      description:       description + (mri_names.empty? ?
                                            '' : " (configured by #{mri_names.join(', ')} Ruby options)")
  )
end

File.write('src/shared/java/org/truffleruby/shared/options/Options.java', ERB.new(<<JAVA).result)
/*
 * Copyright (c) 2016, 2018 Oracle and/or its affiliates. All rights reserved. This
 * code is released under a tri EPL/GPL/LGPL license. You can use it,
 * redistribute it and/or modify it under the terms of the:
 *
 * Eclipse Public License version 1.0
 * GNU General Public License version 2
 * GNU Lesser General Public License version 2.1
 */
package org.truffleruby.shared.options;

// This file is automatically generated by options.yml with 'jt build options'

import javax.annotation.Generated;

@Generated("tool/generate-options.rb")
public class Options {

    <% options.each do |o| %>public final <%= o.type %> <%= o.constant %>;
    <% end %>
    Options(OptionsBuilder builder) {
    <% options.each do |o| %>    <%= o.constant %> = builder.getOrDefault(OptionsCatalog.<%= o.constant %><%= o.reference_default ? ', ' + o.default : '' %>);
    <% end %>}

    public Object fromDescription(OptionDescription<?> description) {
        switch (description.getName()) {
            <% options.each do |o| %>case "ruby.<%= o.name %>":
                return <%= o.constant %>;
            <% end %>default:
                return null;
        }
    }
}
JAVA

File.write('src/shared/java/org/truffleruby/shared/options/OptionsCatalog.java', ERB.new(<<JAVA).result)
/*
 * Copyright (c) 2016, 2018 Oracle and/or its affiliates. All rights reserved. This
 * code is released under a tri EPL/GPL/LGPL license. You can use it,
 * redistribute it and/or modify it under the terms of the:
 *
 * Eclipse Public License version 1.0
 * GNU General Public License version 2
 * GNU Lesser General Public License version 2.1
 */
package org.truffleruby.shared.options;

// This file is automatically generated by options.yml with 'jt build options'

import javax.annotation.Generated;

@Generated("tool/generate-options.rb")
public class OptionsCatalog {

    <% options.each do |o| %>public static final <%= o.type_description %> <%= o.constant %> = new <%= o.type_description %>(
            "ruby.<%= o.name %>",
            "<%= o.description %>",
            <%= if o.mri_names.empty?
                  'null'
                else
                  'new String[]{' + o.mri_names.map(&:inspect).join(', ') + '}'
                end %>,
            <%= o.reference_default ? o.default + '.getDefaultValue()' : o.default %>);
    <% end %>
    public static OptionDescription<?> fromName(String name) {
        switch (name) {
            <% options.each do |o| %>case "ruby.<%= o.name %>":
                return <%= o.constant %>;
            <% end %>default:
                return null;
        }
    }

    public static OptionDescription<?>[] allDescriptions() {
        return new OptionDescription<?>[] {<% options.each do |o| %>
            <%= o.constant %>,<% end %>
        };
    }

}
JAVA
